package SquarePackage;
//import java.util.*;
//import java.lang.*;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;

/**
 * 	A class representing a square within a dungeon of a roleplaying game,
 *  these squares at all times have a certain temperature, humidity, slipperyness and inhabitability.
 *  Each square can have borders in six directions. These squares connect to become a game world.
 *  
 *  @invar	The temperature must be a valid temperature
 *  		| isValidTemperature(this.getTemperature())
 *  @invar	The relative humidity cannot be negative, or bigger than 100.
 *  		| isValidHumidity(this.getHumidity())
 *  @invar	The amount of borders must be between 0 and 6
 *  		| getBorderAmount() > 0 && getBorderAmount() <= 6
 *  @invar	The maximum temperature must be valid.
 *  		|canHaveAsMAX_TEMPERATURE(this.getTemp(),getMaximumTemp())
 *  @invar	The minimum temperature must be valid
 *  		|canHaveAsMIN_TEMPERATURE(this.getTemp(),getMinimumTemp())
 *  @invar	The temperature domain must be valid
 *  		|canHaveAsTemperatureDomain(this.getMinimumTemp(), getMaximumTemp())
 *  
 *  @author Florian & Maaike
 *  @version 1.2
 *  
 */
public class Square {
	/**
	 * Initialize the new square with given humidity and a given temperature in a specified scale, being Celsius, Kelvin or Fahrenheit.
	 * 
	 * @param	temperature
	 * 			This is the temperature of a square. Temperatures can be given in Celsius, Kelvin or Fahrenheit.
	 * 			Calculations are made in Celsius. So every temperature is converted to Celsius before calculations. The temperature influences
	 * 			the cold damage, heat damage, slippery and inhabitability of a square.
	 * @param	humidity
	 *  		This is the humidity of a square. The humidity is expressed in percentage. It cannot be negative or 
	 *  		bigger than 100. Humidity influences rust damages, slippery and inhabitability of a square.
	 * @param	scale
	 * 			This is the scale in which the temperature is given. Scale must be Celsius, Kelvin or Fahrenheit.
	 * @throws	IllegalArgumentException
	 * 			Scale cannot be anything else but Celsius, Kelvin or Fahrenheit.
	 * 			| !scale.isValidScale()
	 * @throws	IllegalArgumentException
	 * 			If the temperature is not a valid temperature
	 * 			| ! isValidTemperature(temperature)
	 * @throws	IllegalArgumentException
	 * 			If the humidity is not a valid humidity
	 * 			| ! isValidHumidity(humidity)	
	 * @post    The temperature of this new square is equal to the given temperature.
	 *          | new.getTemperature() == temperature
	 * @post    The humidity is equal to the given humidity
	 *          | new.getHumidity() == humidity
	 * @post    The maximum temperature is initializated at 5000
	 *          | new.getMaximumTemp() == 5000
	 * @post    The minimum temperature is initializated at -200
                | new.getMinimumTemp() == -200
	 */
	public Square(double temperature, double humidity, Temperature scale) throws IllegalArgumentException {
		double newTemperature;
		if (! Temperature.isValidScale(scale)){
			throw new IllegalArgumentException("This is not a valid scale");
		}
		if (scale == Temperature.KELVIN) {
			newTemperature = scale.convertTemperature(temperature,Temperature.CELSIUS);
		}
		if (scale == Temperature.FAHRENHEIT) {
			newTemperature = scale.convertTemperature(temperature,Temperature.CELSIUS);
		}
		else {
			newTemperature = temperature;
			setMaximumTemp(5000);
			setMinimumTemp(-200);
			if (!isValidTemperature(newTemperature)) {
				throw new IllegalArgumentException("the temperature is not valid");
			}
			if (!isValidHumidity(humidity)) {
				throw new IllegalArgumentException("the humidity is not valid");
			}
			setTemperature(temperature);
			setHumidity(humidity);
		}
	}

	/**
	 * Initialize the new square with given Temperature and given Humidity.
	 * 
	 * @param	temperature
	 *  		This is the temperature of a square. Temperatures must be given in Celsius.
	 *  		The temperature influences the cold damage, heat damage, slippery and inhabitability of a square. 
	 * @param	humidity
	 *  		This is the humidity of a square. The humidity is expressed in percentage. It cannot be negative or 
	 *  		bigger than 100. Humidity influences rust damages, slippery and inhabitability of a square.
	 * @effect	This square is initialized in the same way a new square would be initialized with the more extended
	 * 			constructor where the temperature scale is Celsius, as this is the standard for the calculations.
	 */
	public Square(double temperature, double humidity) throws IllegalArgumentException {
		this(temperature,humidity,Temperature.CELSIUS);
	}

	/**
	 * Initialize the new square with temperature 0°C and humidity 0%.
	 */
	public Square(){
		this(0,0,Temperature.CELSIUS);
	}

	/**
	 *  this variable represents the temperature for a square 
	 */
	private double temperature;

	/**
	 * 	this constant represents the minimal temperature for a square
	 */
	private double MIN_TEMPERATURE;

	/**
	 *  this constant represents the maximum temperature for a square
	 */
	private double MAX_TEMPERATURE;


	// STUK OVER TEMPERATUUR

	/**
	 * Inspector that retrieves the current temperature of the square.
	 * @return the current temperature for the square
	 */
	@Basic @Raw
	public double getTemp(){
		return this.temperature;
	}

	/**
	 * Inspector that retrieves the minimal temperature of a square. This is the lowest possible value of the temperature of a square.
	 * @return the minimum temperature for the square
	 */
	@Basic @Raw
	public double getMinimumTemp(){
		return MIN_TEMPERATURE;
	}

	/**
	 * Inspector that retrieves the maximal temperature of a square. This is the lowest possible value of the temperature of a square.
	 * @return the maximum temperature for the square
	 */
	@Basic @Raw
	public double getMaximumTemp(){
		return MAX_TEMPERATURE;
	}

	/**
	 * Mutator to change the minimum temperature.
	 * 
	 * @param 	MIN_TEMPERATURE
	 * 			the new lowest possible temperature for the square
	 * @post	MIN_TEMPERATURE has been changed to the value that we have specified
	 * 			| new.getMinimumTemp() = newMIN_TEMPERATURE
	 * @throws	IllegalArgumentException
	 * 			the given value is not allowed if the newMIN_TEMPERATURE value is higher than the actual current temperature
	 * 			| ! canHaveAsMIN_TEMPERATURE(getTemperature(),newMIN_TEMPERATURE)
	 * @throws	IllegalArgumentException
	 * 			the given value is not allowed if the newMIN_TEMPERATURE value is higher than the MAX_TEMPERATURE
	 * 			| ! canHaveAsTemperatureDomain(newMIN_TEMPERATURE, getMaximumTemp())
	 */
	@Raw
	public void setMinimumTemp(double newMIN_TEMPERATURE) throws IllegalArgumentException {
		if(!canHaveAsMIN_TEMPERATURE(getTemp(),newMIN_TEMPERATURE)) {
			throw new IllegalArgumentException("The given new minimum temperature exceeds the current temperature of the square");
		}
		if(!canHaveAsTemperatureDomain(newMIN_TEMPERATURE, getMaximumTemp())) {
			throw new IllegalArgumentException("The given minimum temperature is equal to or higher than the maximum temperature");
		}
		this.MIN_TEMPERATURE= newMIN_TEMPERATURE;
	}

	/**
	 * Mutator to change the maximum temperature.
	 * 
	 * @param 	MAX_TEMPERATURE
	 * 			the new highest possible temperature for the square
	 * @post	MAX_TEMPERATURE has been changed to the value that we have specified
	 * 			| new.getMaximumTemp() = newMAX_TEMPERATURE
	 * @throws	IllegalArgumentException
	 * 			the given value is not allowed if the newMAX_TEMPERATURE value is lower than the actual current temperature
	 * 			| ! canHaveAsMAX_TEMPERATURE(getTemperature(),newMAX_TEMPERATURE)
	 * @throws	IllegalArgumentException
	 * 			the given value is not allowed if the newMAX_TEMPERATURE value is less than the MIN_TEMPERATURE
	 * 			| ! canHaveAsTemperatureDomain(getMinimumTemp(), newMAX_TEMPERATURE)
	 */
	@Raw
	public void setMaximumTemp(double newMAX_TEMPERATURE) throws IllegalArgumentException {
		if(!canHaveAsMAX_TEMPERATURE(getTemp(),newMAX_TEMPERATURE)) {
			throw new IllegalArgumentException("The given new maximum temperature is less than the current temperature of the square");
		}
		if(!canHaveAsTemperatureDomain(getMinimumTemp(), newMAX_TEMPERATURE )) {
			throw new IllegalArgumentException("The given maximum temperature is equal to or less than the minimum temperature");
		}
		this.MAX_TEMPERATURE= newMAX_TEMPERATURE;
	}

	/**
	 * Mutator to change the temperature domain, thus changes the minimum and maximum temperature at once.
	 * 
	 * @param	newMIN_TEMPERATURE
	 * 			The new minimum temperature.
	 * @param	newMAX_TEMPERATURE
	 * 			The new maximum temperature.
	 * @throws	IllegalArgumentException
	 * 			caused by the use of previous methodes
	 * 			
	 */
	public void setTemperatureDomain(double newMIN_TEMPERATURE, double newMAX_TEMPERATURE) throws IllegalArgumentException{
		setMaximumTemp(newMAX_TEMPERATURE);
		setMinimumTemp(newMIN_TEMPERATURE);
	}

	/**
	 * Check whether the given minimum temperature is allowed
	 * @param 	temperature
	 *          The temperature to check
	 * @param 	newMIN_TEMPERATURE
	 *          The lower limit for the temperature to check.
	 * @return 	True if and only if the variable newMIN_TEMPERATURE is smaller or equal to the variable temperature.
	 *          | result == (temperature >= newMIN_TEMPERATURE)
	 */
	private boolean canHaveAsMIN_TEMPERATURE(double temperature, double newMIN_TEMPERATURE){
		return temperature >= newMIN_TEMPERATURE && newMIN_TEMPERATURE>=-273.15 && canHaveAsTemperatureDomain(newMIN_TEMPERATURE,getMaximumTemp()) ;
	}

	/**
	 * Check whether the given maximum temperature is allowed
	 * @param	temperature
	 *        	The temperature to check
	 * @param	newMAX_TEMPERATURE
	 *          The upper limit for the temperature to check.
	 * @return	True if and only if the variable newMAX_TEMPERATURE is larger or equal to the variable temperature.
	 *          | result == (temperature <= newMAX_TEMPERATURE)
	 */
	private boolean canHaveAsMAX_TEMPERATURE(double temperature,double newMAX_TEMPERATURE){
		return temperature <= newMAX_TEMPERATURE && newMAX_TEMPERATURE>=-273.15 && canHaveAsTemperatureDomain(getMinimumTemp(), newMAX_TEMPERATURE) ;
	}

	/**
	 * A method that checks the correctness of the domain specified by newMIN_TEMPERATURE and newMAX_TEMPERATURE
	 * 
	 * @param	newMIN_TEMPERATURE
	 * 		 	The minimum temperature to check
	 * @param	newMAX_TEMPERATURE
	 * 			the maximum temperature to check
	 * @return
	 */
	private boolean canHaveAsTemperatureDomain(double newMIN_TEMPERATURE, double newMAX_TEMPERATURE){
		if((Double.compare(newMIN_TEMPERATURE,newMAX_TEMPERATURE))<0)
			return true;
		return false;
	}

	/**
	 * Check whether the temperature is valid
	 * 
	 * @param 	temperature
	 * 			the temperature to check
	 * @return	True if and only if the value of temperature lies between 
	 * 			the upper and lower limit for temperature
	 * 			| result == (temperature >= getMinimumTemp()) && (temperature <= getMaximumTemp()) && (temperature != null)
	 */
	@Raw
	public boolean isValidTemperature(double temperature) throws IllegalArgumentException {
		try {
			return canHaveAsMIN_TEMPERATURE(temperature, getMinimumTemp()) &&
			canHaveAsMAX_TEMPERATURE(temperature,getMaximumTemp());
		}	catch (NullPointerException exc) {
			throw new IllegalArgumentException("Non-effective temperature");}
	}

	/**
	 * Mutator to set the temperature
	 * 
	 * @param	temperature
	 * 			the new temperature given to the square
	 * @throws 	IllegalArgumentException
	 * 			caused by the use of previous methodes
	 */
	public void setTemperature(double temperature) throws IllegalArgumentException{

		if (isValidTemperature(temperature)) {
			this.temperature = temperature;
		}
	}

	/**
	 * Inspector to get the temperature in Fahrenheit
	 * 
	 * @param	temperature
	 * 			the initial temperature in Celsius
	 * @return	the temperature in Fahrenheit
	 */
	@Basic
	public double getTempInFahrenheit(double temperature) {
		Temperature scale = Temperature.CELSIUS;
		return (scale.convertTemperature(temperature, Temperature.FAHRENHEIT));
	}

	/**
	 * Inspector to get the temperature in Kelvin
	 * 
	 * @param	temperature
	 * 			the initial temperature in Celsius
	 * @return	the temperature in Kelvin
	 */
	@Basic
	public double getTempInKelvin(double temperature) {
		Temperature scale = Temperature.CELSIUS;
		return (scale.convertTemperature(temperature, Temperature.KELVIN));
	}

	// stuk over vochtigheidsgraad   -   in nominal programming

	/**
	 *	this variable represents the humidity
	 */
	private double humidity;

	/**
	 * get the humidity of the square
	 * @return the humidity of the square
	 */
	@Raw @Basic
	public double getHumidity(){
		return this.humidity;
	}

	/**
	 * Set the humidity of the square to a given value
	 * @pre		the humidity has to be a valid percentage between 0 and 100
	 * 			|isValidHumidity(humidity)
	 * @pre		the humidity value is not null
	 * 			|humidity!=null
	 * @param	humidity
	 * 			the new humidity for this square
	 * @post	the humidity of the square is set to the given humidity
	 * 			|new.getHumidity=humidity
	 */
	@Raw 
	public void setHumidity(double humidity){
		assert isValidHumidity(humidity);
		this.humidity = humidity;
	}
	/**
	 * check the acceptability of humidity
	 * @param		humidity
	 * 				the humidity we want to check
	 * @return		true if and only if the humidity lies between 0 and 100 and is not null
	 * 				|if(0<=humidity&&humidity<=100)
	 * 				|result=true
	 */
	@Raw
	public boolean isValidHumidity(double humidity)throws IllegalArgumentException{
		try{
			return (100 >= humidity) && (humidity >= 0);}
		catch(NullPointerException exc){
			throw new IllegalArgumentException("non effective number");
		}
	}
	/**
	 * rounding to 2 decimal places
	 * @param 	number
	 * 			the number to roundOff
	 * @pre		number cannot be too big							
	 * @return	the number rounded off
	 */
	public double roundOff(double number){
		assert Double.MAX_VALUE/100 > number;					
		return ((Long)(Math.round(number*100)/100)).doubleValue();		

	}

	// STUK OVER DAMAGE
	private static int HEAT_DAMAGE_RATE = 15;
	private static int HEAT_DAMAGE_TEMPERATURE = 35;
	/**
	 * This method specifies the damage inflicted on a player by heat.
	 * 		This happens when creatures are situated on a square with a temperature above a certain temperature.
	 * @return 	The amount of damage calculated against the minimum temperature needed to inflict damage.
	 * 			0 is returned if there is no damage to be done.
	 *    	 	| if (getTemp() > getHEAT_DAMAGE_TEMPERATURE())
	 *     		| return (getTemp()- getHEAT_DAMAGE_TEMPERATURE())/getHEAT_DAMAGE_RATE()
	 *     		| else return 0			
	 */
	public int heatDamage(){

		if(((Double)getTemp()).intValue() > getHEAT_DAMAGE_TEMPERATURE()) {
			return ((((((Double)getTemp()).intValue()) - getHEAT_DAMAGE_TEMPERATURE()) / getHEAT_DAMAGE_RATE()));

		}								
		return 0;
	}
	/**
	 * Return the current heat damage rate that applies to ALL squares.
	 * 			This rate gives the temperature needed for 1 damage point.
	 * @return 	the HEAT_DAMAGE_RATE
	 * 			| result == HEAT_DAMAGE_RATE
	 */
	@Basic @Raw
	public int getHEAT_DAMAGE_RATE(){
		return HEAT_DAMAGE_RATE;
	}
	/**
	 *  mutator to change the HEAT_DAMAGE_RATE
	 * @param	HEAT_DAMAGE_RATE
	 * 			the new HEAT_DAMAGE_RATE we want to specify
	 */
	@Raw
	public static void setHEAT_DAMAGE_RATE(int heatDamageRate){
		if(heatDamageRate>0){
			Square.HEAT_DAMAGE_RATE=heatDamageRate;
		}
	}
	/**
	 * inspector to get the minimum heat to inflict damage
	 * @return	HEAT_DAMAGE_TEMPERATURE
	 * 			|result == HEAT_DAMAGE_TEMPERATURE
	 * 		
	 */
	public int getHEAT_DAMAGE_TEMPERATURE(){
		return HEAT_DAMAGE_TEMPERATURE;
	}
	/**
	 * mutator to change the minimum temperature for inflicting heatDamage
	 * @param	HEAT_DAMAGE_TEMPERATURE
	 * 			the new HEAT_DAMAGE_TEMPERATURE we want to specify
	 */
	public static void setHEAT_DAMAGE_TEMPERATURE(int heatDamageTemperature){
		if(heatDamageTemperature>0){
			Square.HEAT_DAMAGE_TEMPERATURE=heatDamageTemperature;
		}
	}
	/**
	 * method to specify both characteritics of heatdamage
	 * @param	heatDamageTemperature
	 * 			the minimum temperature heat inflicts damage on creatures
	 * @param 	heatDamageRate
	 * 			the rate at which damage points are calculated
	 */
	public static void setHeat_Damage_Values(int heatDamageTemperature,int heatDamageRate){
		setHEAT_DAMAGE_TEMPERATURE(heatDamageTemperature);
		setHEAT_DAMAGE_RATE(heatDamageRate);
	}
	/**
	 * constant representing the temperature needed for colddamage
	 */
	public static final int COLD_DAMAGE_TEMPERATURE=-5;
	/**
	 * constant representing the rate of damage per degrees when colddamage occurs
	 */
	public static final int COLD_DAMAGE_RATE=10;
	/**
	 * Return the cold damage caused by the low temperature.
	 * 			This happens when creatures are situated on a square with a temperature below the COLD_DAMAGE_TEMPERATURE
	 * @return	the amount of damage this square will cause if the temperature is below -5 degrees.
	 * 			|if(getTemp()<-5)
	 * 			|return ((-getTemp())-5)/10
	 * 			|else return 0
	 */
	public int coldDamage(){
		if(getTemp()< COLD_DAMAGE_TEMPERATURE)
			return (int)((Math.abs( getTemp())) - Math.abs(COLD_DAMAGE_TEMPERATURE))/COLD_DAMAGE_RATE;
		return 0;
	}
	/**
	 * constant specifying the minimum humidity for rust damage
	 */
	private int RUST_DAMAGE_MINIMUM=30;
	/**
	 * constant specifying the amount of damage inflicted by rust
	 */
	private int RUST_DAMAGE_RATE=7;
	/**
	 * inspector to retrieve the minimum humidity for rust damage
	 */
	public int getRustDamageMinimum(){
		return RUST_DAMAGE_MINIMUM;
	}
	public int getRustDamageRate(){
		return RUST_DAMAGE_RATE;
	}
	/**
	 * This method returns the rust damage caused by humidity to metal objects situated within the square
	 * @return	the damage this square will cause if the  humidity is higher than 30 percent
	 * 			| if(getHumidity()>=30)
	 * 			| return ((getHumidity()-30)/7)
	 */
	public int rustDamage(){
		if(getHumidity()>RUST_DAMAGE_MINIMUM){
			return ((Double)((getHumidity()-RUST_DAMAGE_MINIMUM)/RUST_DAMAGE_RATE)).intValue();
		}
		return 0;
	}
	// OVER INHABITABILITY
	/**
	 *  inspector to retrieve the inhabitability of a square
	 *  @return	the inhabitability of the square
	 */
	public double getInhabitability()
	{
		return (-(Math.sqrt(Math.pow(heatDamage(), 3)))/(Math.sqrt(101-getHumidity()))-Math.sqrt(coldDamage()));
	}
	
	
	
	
	
	
	// OVER BORDERS
	/**
	 * Constant referring to the number of borders a square has.
	 */
	private static final int numberOfBorders=6;
	/**
	 * 	this array of 6 booleans represents the fact that the square has a border in the direction specified by its number
	 */
	private boolean[] border = new boolean[numberOfBorders-1];   
	/**
	 * A method to set a border in one of the six possible directions
	 * @param 	direction 
	 * 			the direction to set the border
	 * @post 	if direction is valid, the square will
	 *       	have a border with the same value as the parameter.
	 *       	In case there is already a border in this direction nothin changes 
	 *       	| if(direction!=null && direction>=0 &&direction<=5 )
	 *       	| new.hasBorder(direction) == true
	 */
	@Basic
	public void setBorder(int direction){
		if(isValidBorder(direction)){
			border[direction-1]=true;
		}  	
	}
	/**
	 * A method to set a border in one of the six possible directions
	 * @param 	direction 
	 * 			the direction to set the border
	 * @post 	if direction is valid, the square will
	 *       	have a border with the same value as the parameter.
	 *       	In case there is already a border in this direction nothin changes 
	 *       	| if(direction!=null && direction>=0 &&direction<=5 )
	 *       	| new.hasBorder(direction) == true
	 */
	@Basic
	public void setBorders(int[] directions){
		for(int direction:directions) {
			if(isValidBorder(direction)) {
				border[direction-1]=true;
			}
		}
	}
	
	/**
	 * A method to check if there is already a border in a specific direction
	 * 
	 * @param 	direction
	 * 			the direction to check
	 * @return 	true the border in this direction exists
	 */
	@Basic
	public boolean hasBorder(int direction){
		if(isValidBorder(direction)) {
			return this.border[direction-1] == true;
		}
		return false;
	}

	/**
	 * A method to check which borders a square have
	 * 
	 * @return	the directions that have a border
	 */
	public int[] getBorders() {
		int amount = this.numberOfBorders();
		int[] borderArray = new int[amount-1];
		int x=0;
		for(int i=1; this.border.length <= 6-i ; i++){
			if(this.hasBorder(i)){
				borderArray[x]=i;
				x++;
			}
		}
		return borderArray;		
	}

	/**
	 * A method to remove a border in a specific direction
	 * @param	direction
	 * 			the direction the border must be deleted
	 * @post	if the square has a border in this direction it will be removed, otherwise nothing will happen
	 * 			|if(this.hasBorder(direction) = true)
	 * 			|new.hasborder(direction)=false 
	 */
	@Basic
	public void removeBorder(int direction){
		if(isValidBorder(direction)){
			border[direction-1]=false;
		}
	}
	/**
	 * A method to remove multiple borders in a specific direction
	 * @param	directions
	 * 			the directions the borders must be deleted
	 * @post	if the square has a border in this direction it will be removed, otherwise nothing will happen
	 * 			|if(this.hasBorder(direction) = true)
	 * 			|new.hasborder(direction)=false 
	 */
	public void removeBorders(int[] directions)
	{
		for(int direction:directions) {
			if(isValidBorder(direction))
				border[direction-1]=false;
		}
	}
	/**
	 * A method to know how many borders a square has.
	 * @return	number of borders
	 */
	@Basic
	public int numberOfBorders(){
		int borderIterator = 0;
		int borderCounter = 0;
		while(borderIterator<=border.length){
			if(hasBorder(borderIterator)==true) {
				borderCounter++;
			}
			borderIterator++;
		}
		return borderCounter;
	}	
	/**
	 * CHEKER FOR MULTIPLE BORDERS
	 * this method checks if the border directions are valid, that is if they are not null and between zero and five.
	 * @param 	directions
	 * 			the directions to check
	 * @return	True if and only if directions are not null and lie between zero and five, both included in the interval
	 * 			|if direction!= null && direction>=1 && direction<=6
	 * 			|result=true
	 * 			|else result=false
	 */
	public boolean isValidBorders(int[] directions){
		boolean validBorderNumber = true;
		if(directions!= null)
			for(int direction : directions){
				if( isValidBorder(direction)&& validBorderNumber==true){
					validBorderNumber = true;
				}
				else{ validBorderNumber = false;}
			}
		return false;	
	}
	/**
	 *
	 * this method checks if the border direction is valid, that is if its not null and between zero and five.
	 * @param 	direction
	 * 			the direction to make the border
	 * @return	True if and only if direction is not null and lies between zero and five, both included in the interval
	 * 			|if direction!= null && direction>=1 && direction<=6
	 * 			|result=true
	 * 			|else result=false
	 */
	public boolean isValidBorder(int direction){
		if((Integer)direction != null && direction>=1 && direction<=6 ){
			return true;
		}
		return false;
	}

	/**
	 * A method to merge this square with another one.
	 * @param	other
	 * 			the other square to merge with
	 * @param	direction
	 * 			the direction in which we want to merge the two squares
	 * @post	if both squares have a border in the direction specified, they will be merged
	 * 			and off course both borders will be removed.
	 * 			|if( this.hasBorder(direction) == true && other.hasBorder(direction)==true)
	 * 			|new.hasBorder(direction)=false && (new other).hasBorder(direction)==false
	 * @post	The new humidity in the given square is equal to the average of the two squares.
	 * 			| new.getHumidity() == calcAverage(getHumidity(),other.getHumidity())
	 *			| (new other).getHumidity() == calcAverage(getHumidity(),other.getHumidity()
	 * @post	The new temperature is calculated with a weight constant to give a weigthed average
	 * 			| new.getTemp()= calcWeightedAverage(getTemp(),other.getTemp())
	 * 			|(new other).getTemp()= calcWeightedAverage(getTemp(),other.getTemp())
	 * @throws	IllegalArgumentException
	 * 			square or direction is not effective
	 * 			| other == null or direction == null	
	 * @throws	IllegalArgumentException
	 * 			| !(this.hasBorder(direction) == true && other.hasBorder(direction) == true)
	 */
	public void mergeWith(int direction, Square other) throws IllegalArgumentException{
		if (!this.canBeMerged(other, direction)){
			throw new IllegalArgumentException("these squares can not be merged");
		}
		other.removeBorder(direction);
		this.removeBorder(direction);

		double weightedAverageTemperature = calcWeightedAverage(other);
		other.setTemperature(weightedAverageTemperature);
		this.setTemperature(weightedAverageTemperature);

		Double averageHumidity = calcAverage(other.getHumidity(),this.getHumidity());
		other.setHumidity(averageHumidity);
		this.setHumidity(averageHumidity);   
	}

	/**
	 * checker to make sure the conditions for merging are satisfied
	 * @param 	other
	 * 			| the square to check the merging to process for.
	 * @param 	direction
	 * 			|the direction in which the squares will be merged
	 * @return
	 * 			|true if and only if 
	 * 			other!=null && this.hasBorder(direction)==true && other.hasBorder(direction)==true
	 */			
	private boolean canBeMerged(Square other, int direction) {
		if(other!=null && this.hasBorder(direction)==true && other.hasBorder(direction)==true){
			return true;
		}
		return false;

	}

	/**
	 * method to calculate a weighted average of 2 numbers against a constant value.
	 * @return	weighted averaged temperature
	 * 			| if (this.getHumidity() == other.getHumidity())
	 * 			| return calcAverage(this.getTemp(), other.getTemp());
	 * 			| else
	 * 			|double averageHumidity= calcAverage(this.getHumidity(), other.getHumidity());
	 *			| double a = ((2-2*WEIGHT_CONSTANT)*averageHumidity)/(this.getHumidity()+other.getHumidity());
	 *			| double weightOne = ((a*this.getHumidity())/(averageHumidity))+WEIGHT_CONSTANT;
	 *			| double weightTwo = ((a*other.getHumidity())/(averageHumidity))+WEIGHT_CONSTANT;
	 *			| return calcAverage(weightOne*this.getTemp(),weightTwo*other.getTemp());
	 */
	public double calcWeightedAverage(Square other){
		if (this.getHumidity() == other.getHumidity()){
			return calcAverage(this.getTemp(), other.getTemp());
		}
		else {
			double averageHumidity= calcAverage(this.getHumidity(), other.getHumidity());
			double a = ((2-2*WEIGHT_CONSTANT)*averageHumidity)/(this.getHumidity()+other.getHumidity());
			double weightOne = ((a*this.getHumidity())/(averageHumidity))+WEIGHT_CONSTANT;
			double weightTwo = ((a*other.getHumidity())/(averageHumidity))+WEIGHT_CONSTANT;
			return calcAverage(weightOne*this.getTemp(),weightTwo*other.getTemp());
		}
	}
	/**
	 * method to calculate the average of two numbers
	 * @param	numberOne
	 * 			the first number to use in the average calculation
	 * @param	numberTwo
	 * 			the second number to use in the average calculation
	 * @return	the average of the two numbers
	 * 			| (numberOne+numberTwo)/2
	 */
	public double calcAverage(double numberOne, double numberTwo){
		return (numberOne+numberTwo)/2;
	}

	/**
	 * Variable referencing the constant for weighted average of temperatures of squares.
	 */
	public static double WEIGHT_CONSTANT = 0.2;

	/**
	 * Inspector to return the value of the weightConstant
	 * @return	the WEIGHT_CONSTANT
	 */
	public static double getWeightConstant(){
		return Square.WEIGHT_CONSTANT;
	}

	/**
	 * this method is used to change the value of the weight constant
	 * @param	weightConstant
	 * 			| the value of the new constant
	 * @throws IllegalArgumentException
	 * 			| the specified value is null or not in a proper domain.
	 */
	public static void setWeightConstant(double weightConstant)throws IllegalArgumentException{
		if(!isValidWeightConstant(weightConstant)){
			throw new IllegalArgumentException("the given value is not in the proper domain or null");
		}
		Square.WEIGHT_CONSTANT = weightConstant;

	}

	/**
	 * this method is a checker for the weight constant value
	 * @return	true if and only if the weighconstant lies between 0.1 en 0.4 and is not the null value
	 * 			| (weightConstant>=0.1)&&(weightConstant<=0.4)
	 */
	public static boolean isValidWeightConstant(double weightConstant){
		return (weightConstant>=0.1)&&(weightConstant<=0.4);
	}



































	// deel over slippery(Defensief)

	/**
	 * Variable referencing if this square is made of slippery material.
	 */
	private boolean madeOfSlipperyMaterial;
	/**
	 * defines the material as slippery or not slippery
	 * 
	 * @param       madeOfSlipperyMaterial
	 *              Boolean if this square is made of slippery material.
	 * @post        The boolean marking the fact that the square is made of slippery material
	 * 				is equal to the given boolean.
	 *              | new.ismadeOfSlipperyMaterial() == madeOfSlipperyMaterial
	 */
	public void setMadeOfSlipperyMaterial(boolean madeOfSlipperyMaterial) {
		this.madeOfSlipperyMaterial = madeOfSlipperyMaterial;
	}        
	/**
	 * Returns if this square is made of slippery material.
	 */
	@Basic
	public boolean getMadeOfSlipperyMaterial() {
		return this.madeOfSlipperyMaterial;
	}
	/**
	 * returns the slipperyness of the floor
	 * 
	 * @return      True if and only if the floor is made of slippery material
	 *				or the temperature is above zero degrees Celsius and the humidity is 100%
	 *				or the temperature is below or equal to zero and the humidity is above 10%.
	 *				| if(madeOfSlipperyMaterial())
	 *              |       result == true
	 *              | else if(getTemp() > 0) && (getHumidity() == 100))
	 *              |      result == true
	 *              | else if((getTemp() <= 0) && (getHumidity() > 10))
	 *              |      result == true
	 *              | else result == false
	 */
	public boolean isSlippery(){ 
		if(getMadeOfSlipperyMaterial())
			return true;
		if((getTemp() > 0) && (getHumidity() == 100))
			return true;
		if((getTemp()) <= 0 && (getHumidity() > 10))
			return true;
		return false;
	}
}







/**
 * constructor:
 * square( temperature, humidity)
 * square()
 * 
 * 
 * mogelijke methodes:
 * 
 * getTemperature()
 * setTemperature( newtemperature)
 * coldDamage(int)
 * heatDamage(int)
 * setMAX_TEMPERATURE()
 * rustDamage(int)
 * getInhabitability()
 * boolean hasBorder(int direction);
 * setBorder(int direction);
 * mergeWith(square other,.. direction)
 * getHumidity()
 * setHumidity()
 * canHaveAsTemperature
 * isValidTemperature
 * canHaveAsHumidity
 * isValidHumidity
 * 
 * 
 * mogelijke variabelen:
 * 
 * temperature(enum) want kelvin en fahrenheit
 * MAX_TEMPERATURE
 * humidity
 * slipperyness
 * numberOfBorders
 * heatCapacity
 * 
 * 
 * 
 */
